package org.vasil.jouikov.testmongodb;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;

import java.util.ArrayList;
import java.util.List;

/**
 * Tests the exceptions thrown by the Java client when replica set members failover and
 * are restarted.  Runs in a loop, trying various operations using various WriteConcerns.
 * Assumes a replica set is available for connections.  On your local machine, this can be
 * started from the shell with:
 *
 * ~/mongo --nodb
 * > var rst = new ReplSetTest({ nodes : 3 })
 * > rst.startSet() // Wait for startup
 * > rst.initiate() // Wait for initialization
 *
 * You may then test failover with:
 *
 * PRIMARY|SECONDARY> rst.stop( 2 ) // assumes 0 is primary
 * PRIMARY|SECONDARY> rst.stop( 1 )
 * PRIMARY|SECONDARY> rst.stop( 0 )
 *
 * The above requires mongod available in your OS path for execution
 */
public class TestShard {

    public static void main(final String [] pArgs) throws Exception {

        List addrs = new ArrayList();
        addrs.add(new ServerAddress("node01" , 27017));
        addrs.add(new ServerAddress("node04" , 27017));
//        addrs.add(new ServerAddress("192.168.1.200" , 30001));
//        addrs.add(new ServerAddress("192.168.1.201" , 30002));
//        addrs.add(new ServerAddress("192.168.1.202" , 30003));

        // Default mongo connection
        final MongoClient mongo = new MongoClient(addrs);
        mongo.setWriteConcern( WriteConcern.NORMAL ); // Default!

	// Mongo connection which validates writes have occurred
        final MongoClient mongoSafe = new MongoClient(addrs);
        mongoSafe.setWriteConcern( WriteConcern.SAFE );

	// Mongo connection which validates writes have occurred in two places
        final MongoClient mongoStrict = new MongoClient(addrs);
        mongoStrict.setWriteConcern( WriteConcern.REPLICAS_SAFE );

	// Mongo connection which reads from secondaries when possible
        final MongoClient mongoSOK = new MongoClient(addrs);
        mongoSOK.setWriteConcern( WriteConcern.NORMAL ); // Default!
        mongoSOK.slaveOk();

        final DBCollection coll = mongo.getDB("test").getCollection("testSystem");
        final DBCollection collSOK = mongoSOK.getDB("test").getCollection("testSystem");
        final DBCollection collSafe = mongoSafe.getDB("test").getCollection("testSystem");
        final DBCollection collStrict = mongoStrict.getDB("test").getCollection("testSystem");

//ReadPreference preference = ReadPreference.primaryPreferred();
//DBCursor cur = new DBCursor(collection, query, null, preference);
        while(true) {
            try {
                final BasicDBObject test = new BasicDBObject("test", "name");

                coll.insert(test);// Does not verify write by default! Fire-and-forget

                System.out.println( "May have wrote to primary!WriteConcern.NORMAL" );

                Thread.sleep(3000);
            }
            catch( MongoException e ){
            	System.out.println( "Could not communicate with replica set!\n" + e);
            }

            try {
                final BasicDBObject test = new BasicDBObject("test", "name");

                collSafe.insert(test); // Verifies write!

                System.out.println( "Wrote to primary!WriteConcern.SAFE" );

                Thread.sleep(3000);
            }
            catch( MongoException e ){
            	System.out.println( "Could not write to primary!\n" + e);
            }

            try {
            	// Reads from primary, so will error when primary down
                DBCursor cursor = coll.find( new BasicDBObject() );
                if( cursor.hasNext() ){
                    DBObject obj = cursor.next();
                }
                cursor.close();

                System.out.println( "Read from primary!WriteConcern.NORMAL" );

                Thread.sleep(3000);
            }
            catch( MongoException e ){
            	System.out.println( "Could not read from primary!\n" + e);
            }

            try {
            	// Read from primary or secondary
                DBCursor cursor = collSOK.find( new BasicDBObject() );
                if( cursor.hasNext() ){
                    DBObject obj = cursor.next();
                }
                cursor.close();

                System.out.println( "Read from secondary or primary!slaveOk WriteConcern.NORMAL" );

                Thread.sleep(3000);
            }
            catch( MongoException e ){
            	System.out.println( "Could not read from anywhere!\n" + e);
            }

            try {
            	// Write to primary and at least one secondary
                final BasicDBObject test = new BasicDBObject("test", "name");

                collStrict.insert(test);

                System.out.println( "Wrote to primary and replicated to one other!WriteConcern.REPLICAS_SAFE" );

                Thread.sleep(3000);
            }
            catch( MongoException e ){
            	System.out.println( "Could not write to primary and replicate to one other!\n" + e);
            }
        }
    }
}
